import { type OptionalFields } from '@gnlab/utils'
import { keywordCompare } from '@gnlab/utils'
import { App } from 'antd'
import dayjs, { type Dayjs } from 'dayjs'
import throttle from 'lodash/throttle'
import { colors } from '@/desktop/styles'
import { toISOString, useThrottledValue } from '@/lib/utils'
import { API } from '@/services/common/api'
import { type Word } from '@/services/common/definition'
import { detectIsGroup, makeContactIdByConversationId, makeContactId } from '@/services/contacts'
import { getFormattedQywxs, type AccountQywx, AccountQywxStatus } from '@/services/qywxs'

export enum Status {
  未开始 = 0,
  发送中 = 1,
  已完成 = 2,
  已取消 = 3,
}

export const statusColors = {
  [Status.未开始]: colors.warning,
  [Status.发送中]: colors.success,
  [Status.已完成]: '',
  [Status.已取消]: colors.gray,
}

export enum Target {
  全部客户 = '全部客户',
  标签客户 = '标签客户',
  客户 = '客户',
  群 = '群聊',
}

export interface ContactInfo {
  id: string
  ownerWxid: string
  conversationId: string
}

export interface Task {
  id: number
  name: string
  targetType: Target

  // 下面字段根据 targetType 决定是否生效
  tagIds: string[] // 客户标签 ID 列表
  contacts: ContactInfo[] // 联系人 ID 列表
  externalWxids: string[] // 要发给“所有客户”或“标签客户”的企微列表

  content: Word[] // 发送内容
  startAt: Dayjs | null // 开始时间，为 null 代表立刻开始
  delay: number // 发送消息的间隔（单位：秒，最小 1 秒）
  status: Status // 任务执行状态
  created: Dayjs // 任务创建时间
}

// ============================================

interface RawTask {
  Id: number
  Name: string | null
  LabelIds: string[] | null
  ConversationIds: { WxId: string; ConversationId: string }[] | null
  WxIds: string[] | null
  SendTime: string | null
  Content: Word[]
  Status: Status
  Delay: number
  CreateTime: string
}
function formatRawTask(raw: RawTask): Task {
  const externalWxids = raw.WxIds ?? []
  const tagIds = raw.LabelIds ?? []
  const conversationIds = raw.ConversationIds ?? []

  const targetType = externalWxids.length
    ? tagIds.length
      ? Target.标签客户
      : Target.全部客户
    : conversationIds.length && detectIsGroup(conversationIds[0]!.ConversationId)
    ? Target.群
    : Target.客户
  return {
    id: raw.Id,
    name: (raw.Name ?? '') || `任务-${raw.Id}`,
    targetType,
    tagIds: targetType === Target.标签客户 ? tagIds : [],
    contacts:
      targetType === Target.客户 || targetType === Target.群
        ? conversationIds.map(({ WxId: ownerWxid, ConversationId: conversationId }) => ({
            id:
              makeContactIdByConversationId(ownerWxid, conversationId) ??
              makeContactId(ownerWxid, conversationId), // 处理联系人是“群”的情况
            ownerWxid,
            conversationId,
          }))
        : [],
    externalWxids:
      targetType === Target.全部客户 || targetType === Target.标签客户 ? externalWxids : [],
    startAt: raw.SendTime === null ? null : dayjs(raw.SendTime),
    content: raw.Content,
    delay: raw.Delay,
    status: raw.Status,
    created: dayjs(new Date(raw.CreateTime)),
  }
}
function toRawTask(task: OptionalFields<Omit<Task, 'created'>, 'id' | 'status'>) {
  return {
    Id: task.id,
    Name: task.name,
    LabelIds: task.targetType === Target.标签客户 ? task.tagIds : [],
    ConversationIds:
      task.targetType === Target.客户 || task.targetType === Target.群
        ? task.contacts.map(info => ({
            wxid: info.ownerWxid,
            conversationId: info.conversationId,
          }))
        : [],
    WxIds:
      task.targetType === Target.全部客户 || task.targetType === Target.标签客户
        ? task.externalWxids
        : [],
    SendTime: task.startAt === null ? null : toISOString(task.startAt),
    Content: task.content,
    Status: task.status,
    Delay: task.delay,
  }
}

export async function saveTask(task: OptionalFields<Omit<Task, 'created'>, 'id' | 'status'>) {
  return API('/BatchMessage/Save', {
    data: toRawTask(task),
  })
}

export async function getTasks() {
  return API('/BatchMessage/List', {
    formatter(items: RawTask[]) {
      return items.map(formatRawTask).sort((a, b) => b.id - a.id)
    },
  })
}

// ============================================

export function useQywxs(initialChoosedWxids?: string[]) {
  const { message } = App.useApp()
  const [qywxs, setQywxs] = useState<AccountQywx[] | null>(null)
  useEffect(() => {
    void getFormattedQywxs('', false).then(res => {
      if (res.success) {
        // 只保留在线的，或已被纳入任务的企微
        const qywxs = res.data.filter(
          qywx =>
            qywx.status === AccountQywxStatus.Online ||
            (initialChoosedWxids ?? []).includes(qywx.wxid),
        )
        setQywxs(qywxs)
      } else {
        void message.error('企微列表加载失败')
        setQywxs([])
      }
    })
  }, [initialChoosedWxids, message])

  // 搜索企微
  const [keyword, rawSetKeyword] = useState('')
  const setKeyword = useMemo(() => throttle(rawSetKeyword, 200), [])
  const [accountId, setAccountId] = useState<string | undefined>(undefined)
  const filteredQywxs = useMemo(() => {
    let filtered = qywxs ?? []
    if (keyword)
      filtered = filtered.filter(
        qywx => keywordCompare(keyword, qywx.friendlyName) || qywx.wxid.includes(keyword),
      )
    if (accountId !== undefined) filtered = filtered.filter(qywx => qywx.accountId === accountId)
    return filtered
  }, [qywxs, keyword, accountId])

  const accounts = useMemo(() => {
    const map = new Map<string, { id: string; name: string }>()
    for (const qywx of qywxs ?? [])
      map.set(qywx.accountId, { id: qywx.accountId, name: qywx.accountName })
    return [...map.values()]
  }, [qywxs])

  return {
    qywxs,
    setKeyword,
    accountId,
    setAccountId,
    filteredQywxs,
    accounts,
  }
}

export function useChooseQywxs(
  initialChoosedWxids: string[],
  allQywxs: AccountQywx[] | null,
  filteredQywxs: AccountQywx[],
) {
  const [wxids, setWxids] = useState(initialChoosedWxids)

  const switchChoose = useCallback((wxid: string) => {
    setWxids(wxids => {
      if (wxids.includes(wxid)) return wxids.filter(v => v !== wxid)
      else return [...wxids, wxid]
    })
  }, [])

  // 有对应的企微的 wxid
  const validWxids = useMemo(
    () => (allQywxs ? wxids.filter(wxid => allQywxs.find(qywx => qywx.wxid === wxid)) : wxids),
    [wxids, allQywxs],
  )

  // 全选 / 反选（在过滤了的企业微信范围内）
  const hasChoosed = useMemo(
    () => !!filteredQywxs.find(qywx => validWxids.includes(qywx.wxid)),
    [filteredQywxs, validWxids],
  )
  const isChoosedAll = useMemo(
    () => filteredQywxs.every(qywx => validWxids.includes(qywx.wxid)),
    [filteredQywxs, validWxids],
  )
  const chooseAll = useCallback(() => {
    const set = new Set(validWxids)
    filteredQywxs.forEach(qywx => set.add(qywx.wxid))
    setWxids([...set])
  }, [filteredQywxs, validWxids])
  const chooseReverse = useCallback(() => {
    const set = new Set(validWxids)
    filteredQywxs.forEach(qywx => (set.has(qywx.wxid) ? set.delete(qywx.wxid) : set.add(qywx.wxid)))
    setWxids([...set])
  }, [filteredQywxs, validWxids])
  const clearChoose = useCallback(() => {
    const set = new Set(validWxids)
    filteredQywxs.forEach(qywx => set.delete(qywx.wxid))
    setWxids([...set])
  }, [filteredQywxs, validWxids])

  return {
    wxids: validWxids,
    switchChoose,
    hasChoosed,
    isChoosedAll,
    chooseAll,
    chooseReverse,
    clearChoose,
  }
}

export type Search = Partial<{
  name: string
  targetType: Target
  status: Status
  createdRange: [Dayjs | null, Dayjs | null]
  startAtRange: [Dayjs | null, Dayjs | null]
}>

export function useSearch(allTasks: Task[] | null) {
  const {
    inputValue: inputSearch,
    value: search,
    setValue: setSearch,
  } = useThrottledValue<Search>({}, 300)

  const tasks = useMemo(() => {
    return (allTasks ?? []).filter(task => {
      const { name, targetType, status, createdRange, startAtRange } = search
      if (name !== undefined && !keywordCompare(name, task.name)) return false
      if (targetType !== undefined && task.targetType !== targetType) return false
      if (status !== undefined && task.status !== status) return false
      if (createdRange) {
        if (createdRange[0] && task.created.isBefore(createdRange[0])) return false
        if (createdRange[1] && task.created.isAfter(createdRange[1])) return false
      }
      if (startAtRange) {
        const startAt = task.startAt ?? task.created
        if (startAtRange[0] && startAt.isBefore(startAtRange[0])) return false
        if (startAtRange[1] && startAt.isAfter(startAtRange[1])) return false
      }
      return true
    })
  }, [allTasks, search])

  return {
    tasks,
    search: inputSearch,
    setSearch,
  }
}
